#include "./include/producer_consumer.h"
#include "./include/S_printModule@windows.h"
#include <stdlib.h>
#include <time.h>

using namespace std;

#define    DEBUG         1      // 定义一个用于调试的宏

/*
 * 定义信号量
 */
Semaphore_t metux=1,            // 互斥信号量，互斥对缓冲区地访问
            empty=BUFFER_SIZE,  // 空槽的数量，初始值为BUFFER_SIZE，表示缓冲区全空
            full=0;             // 已填充数据的个数，初始值为0，表示还没有数据

/*
 * 共享变量
 * 缓冲区 buffer 由生产者和消费者共享
 * 下标 pi 由生产者独占， ci 由消费者独占
 */
int buffer[BUFFER_SIZE]={};  // 共享缓冲区，初始值为 0，0 表示没有数据
int pi=0;          // pi 表示生产者每次将数据加入到 buffer[pi] 缓冲槽中
int ci=0;          // ci 表示消费者每次从 buffer[ci] 的缓冲槽槽中取数据


/*
 * 生产数据
 */
int produce_data()
{
    srand( (unsigned)time(0) );
    return  rand() % 98 + 1;       // 生成[1,100)之间的随机正整数
}

/*
 * 函数功能：
 *     将数据加入缓冲区，这里仅输出一句话作为模拟
 * 参数：
 *     无
 * 返回值：
 *     void
 */
void append(int data, int &returnIndex)
{
    returnIndex=pi;
    buffer[pi]=data;
    pi = (pi+1) % BUFFER_SIZE;

    /*
     * 可视化到控制台输出
     */
    visual2console(data,'p');
}

/*
 * 函数功能：
 *     生产者，负责不断地生产数据
 * 参数：
 *     int &returnIndex: 通过引用返回添加数据的下标
 * 返回值：
 *     void
 */
void producer(int &returnIndex)
{
    int data;
    data=produce_data();  // 生产数据

    P(&empty);                  // 申请一个空槽
    P(&metux);                  // 申请进入临界区 
    append(data, returnIndex);  // 将数据加入缓冲区
    V(&metux);                  // 离开临界区
    V(&full);                   // 增加一个非空槽
}

/*
 * 函数功能：
 *     消费一个数据，这里仅输出一句话作为模拟
 * 参数：
 *     无
 * 返回值：
 *     void
 */
void consume_data()
{
    //
    // TODO 
    //
}

/*
 * 函数功能：
 *     从缓冲区拿走一个数据，这里仅输出一句话作为模拟
 * 参数：
 *     无
 * 返回值：
 *     void
 */
void remove(int &index)
{
    buffer[ci]=0;
    index=ci;
    ci = (ci+1) % BUFFER_SIZE;

    /*
     * 可视化到控制台输出
     */
    visual2console(0,'c');    
}

/*
 * 函数功能：
 *     消费者，不断地消费数据
 * 参数：
 *     无
 * 返回值：
 *     void
 */
void consumer(int &returnIndex)
{
    P(&full);              // 申请一个非空槽
    P(&metux);             // 互斥对缓冲区地访问
    remove(returnIndex);   // 从缓冲区取走一个数据
    V(&metux);             // 离开临界区
    V(&empty);             // 取出一个数据后增加一个空槽
    consume_data();        // 消费数据  
}    

